package com.load.ctrls.imp;

import java.io.*;
import java.net.*;
import java.util.*;

import org.apache.log4j.*;
import org.tmatesoft.svn.core.*;

import com.database.daos.*;
import com.database.objects.*;
import com.load.batch.*;
import com.load.ctrls.*;
import com.load.factories.*;
import com.load.loaders.imp.*;
import com.load.utils.*;

public class LoadVersionCtrl implements ILoadVersionCtrl, Serializable {

	private static final long serialVersionUID = -1333595250142964295L;

	private static Logger logger = Logger.getLogger("load.repository");

	private IProjectDao projectDao;

	private IElementDao elementDao;

	private IProjectCtrl projectCtrl;

	private IElementCtrl elementCtrl;

	private IContributionCtrl contributionCtrl;

	private LoaderCommit loaderCommit;

	@Override
	public void load(Project project, BatchExecutor executor) throws SVNException {
		if (executor.requiresProxy()) {
			Authenticator.setDefault(new SimpleAuthenticator(executor.getProxyName(), executor.getProxyPassword()));
		}

		executor.setStatus("Configurating Load ...");

		VersionRepository repository = project.getVersionRepository();
		configureRepository(repository);
		saveProjectAndDevelopers(project);

		executor.setTotalLoad(repository.getNumEntries());

		logger.info("START LOAD CONTRIBUTION");
		logger.info("REPOSITORY: " + repository.getNumEntries() + " entries");
		for (SVNLogEntry entry : repository.getEntries()) {
			try {
				Commit commit = buildCommit(project, entry);
				if (repository.getType().impliesFile()) {
					loaderCommit.loadChilds(repository.getSvnRepository(), repository.getType(), commit, executor);
				}
				executor.addSuccessLoaded("Loading Commit " + commit.getNumber() + " ...");
			} catch (Exception e) {
				e.printStackTrace();
				executor.addErrorsLoaded("Error Loading Commit " + entry.getRevision());
				logger.error("ERROR: Processing commit " + entry.getRevision());
			}
		}
		logger.info("FINISH LOAD CONTRIBUTION");

		logger.info("START COUNT CONTRIBUTION");
		for (Developer developer : project.getDevelopers()) {
			executor.addSuccessLoaded("Counting contributions for the developer: " + developer.getName());
			logger.info("DEVELOPER: " + developer.getName());
			elementCtrl.calculateConstantineCohesionForClasses(developer);

			List<Element<?, ?>> commits = elementDao.findCommitsByDeveloper(developer);
			contributionCtrl.calculateContributions(developer, project.getVersionRepository(), commits);
		}
	}

	private void configureRepository(VersionRepository repository) throws SVNException {
		repository.processUrl();
		repository.setSvnRepository();
		repository.setEntries();
		logger.info("REPOSITORY: " + repository.getNumEntries() + " entries");
	}

	private void saveProjectAndDevelopers(Project project) {
		logger.info("START LOAD GENERAL DATA");
		Project projectDB = projectDao.getByName(project.getName());
		if (projectDB != null) {
			projectDB.setVersionRepository(project.getVersionRepository());
			project.clone(projectDB);
		}

		VersionRepository repository = project.getVersionRepository();
		for (SVNLogEntry entry : repository.getEntries()) {
			if (entry.getAuthor() != null) {
				project.addDeveloper(new Developer(entry.getAuthor(), project));
			}
		}

		logger.info("DEVELOPERS: " + project.getDevelopers());
		projectCtrl.completeData(project);
		projectDao.saveElement(project);
		logger.info("FINISH LOAD GENERAL DATA");
	}

	private Commit buildCommit(Project project, SVNLogEntry entry) throws Exception {
		Commit commit = elementDao.getCommitByNumber(project, entry.getRevision());
		if (commit == null) {
			commit = CommitFactory.createCommit(project, entry);
			elementDao.saveElement(commit);
		}
		commit.setEntry(entry);
		return commit;
	}

	public void setProjectDao(IProjectDao projectDao) {
		this.projectDao = projectDao;
	}

	public void setElementDao(IElementDao elementDao) {
		this.elementDao = elementDao;
	}

	public void setProjectCtrl(IProjectCtrl projectCtrl) {
		this.projectCtrl = projectCtrl;
	}

	public void setElementCtrl(IElementCtrl elementCtrl) {
		this.elementCtrl = elementCtrl;
	}

	public void setContributionCtrl(IContributionCtrl contributionCtrl) {
		this.contributionCtrl = contributionCtrl;
	}

	public void setLoaderCommit(LoaderCommit loaderCommit) {
		this.loaderCommit = loaderCommit;
	}

}